java集合类源码分析之List(二)
这一节主要介绍List接口的几个实现类的区别:
1.线程安全
Vector是线程安全的,而ArrayList和LinkedList是非线程安全的。从源码中我们可知,Vector类中的方法大部分都是同步的,即被synchronized关键字修饰;而那些没有被synchronized关键字修饰的方法都是通过调用其他同步方法或者采用同步代码块来达到同步的。
1 public synchronized void addElement(E obj) { 2 modCount++; 3 ensureCapacityHelper(elementCount + 1); 4 elementData[elementCount++] = obj; 5 } 6 7 public synchronized boolean removeElement(Object obj) { 8 modCount++; 9 int i = indexOf(obj); 10 if (i >= 0) { 11 removeElementAt(i); 12 return true; 13 } 14 return false; 15 } 16 17 public synchronized E get(int index) { 18 if (index >= elementCount) 19 throw new ArrayIndexOutOfBoundsException(index); 20 21 return elementData(index); 22 } 23 24 public synchronized void insertElementAt(E obj, int index) { 25 modCount++; 26 if (index > elementCount) { 27 throw new ArrayIndexOutOfBoundsException(index 28 + " > " + elementCount); 29 } 30 ensureCapacityHelper(elementCount + 1); 31 System.arraycopy(elementData, index, elementData, index + 1, elementCount - index); 32 elementData[index] = obj; 33 elementCount++; 34 }
1 public boolean contains(Object o) { 2 return indexOf(o, 0) >= 0; 3 } 4 5 public synchronized int indexOf(Object o, int index) { 6 if (o == null) { 7 for (int i = index ; i < elementCount ; i++) 8 if (elementData[i]==null) 9 return i; 10 } else { 11 for (int i = index ; i < elementCount ; i++) 12 if (o.equals(elementData[i])) 13 return i; 14 } 15 return -1; 16 } 17 18 public Enumeration<E> elements() { 19 return new Enumeration<E>() { 20 int count = 0; 21 22 public boolean hasMoreElements() { 23 return count < elementCount; 24 } 25 26 public E nextElement() { 27 synchronized (Vector.this) { 28 if (count < elementCount) { 29 return elementData(count++); 30 } 31 } 32 throw new NoSuchElementException("Vector Enumeration"); 33 } 34 }; 35 }
2.适用条件
ArrayList:适用于随机访问比较频繁(自带索引),而插入和删除操作较少的情况下;
LinkedList:适用于插入和删除比较频繁(修改前后节点),而随机访问较少的情况下;
Vector:适用于要求线程安全(方法同步),执行效率不高,数据量大的情况下。
3.内存消耗
在内存消耗方面,LinkedList < ArrayList < Vector。
LinkedList由于采用链表的形式实现,所以不需要指定容量大小,因此内存消耗较少;而ArrayList和Vector都是采用数组的形式实现,需要指定初始容量的大小(默认都是10),并且当容量不够时都需要进行扩容,在扩容方面:
- ArrayList每次只增加当前数组长度的一半,即newCapacity = oldCapacity + (oldCapacity >> 1),源码中扩容的方法如下:
1 private void grow(int minCapacity) { 2 // overflow-conscious code 3 int oldCapacity = elementData.length; 4 int newCapacity = oldCapacity + (oldCapacity >> 1); 5 if (newCapacity - minCapacity < 0) 6 newCapacity = minCapacity; 7 if (newCapacity - MAX_ARRAY_SIZE > 0) 8 newCapacity = hugeCapacity(minCapacity); 9 // minCapacity is usually close to size, so this is a win: 10 elementData = Arrays.copyOf(elementData, newCapacity); 11 }
- Vector每次增加当前数组长度的一倍,即newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity),capacityIncrement是人为指定的扩容大小,默认为0,源码中扩容的方法如下:
1 private void grow(int minCapacity) { 2 // overflow-conscious code 3 int oldCapacity = elementData.length; 4 int newCapacity = oldCapacity + ((capacityIncrement > 0) ? 5 capacityIncrement : oldCapacity); 6 if (newCapacity - minCapacity < 0) 7 newCapacity = minCapacity; 8 if (newCapacity - MAX_ARRAY_SIZE > 0) 9 newCapacity = hugeCapacity(minCapacity); 10 elementData = Arrays.copyOf(elementData, newCapacity); 11 }
综上所述,Vector对内存的消耗比较高,其次是ArrayList。
4.排序问题
有了数据的存储方法(List),当然要考虑到数据在集合中的顺序问题,下面对List集合的排序做一个简单的总结:
- List集合中的排序通常调用工具类Collections中的静态方法来实现,常用的方法有:sort、reverse、shuffle、min、max等。
1 LinkedList<Integer> linkedList = new LinkedList<Integer>(); 2 linkedList.add(100); 3 linkedList.add(120); 4 linkedList.add(110); 5 Collections.sort(linkedList);//升序排列 6 System.out.println(linkedList); 7 8 Collections.sort(linkedList, new Comparator<Integer>() { 9 10 @Override 11 public int compare(Integer o1, Integer o2) { 12 // TODO Auto-generated method stub 13 // return 0; 14 return o2.compareTo(o1); //降序排列 15 } 16 }); 17 System.out.println(linkedList); 18 19 Collections.shuffle(linkedList);//随机乱序 20 System.out.println(linkedList); 21 22 Collections.reverse(linkedList);//逆序 23 System.out.println(linkedList); 24 25 System.out.println(Collections.min(linkedList));//最小值 26 System.out.println(Collections.max(linkedList));//最大值
- List集合的排序还可以通过有序集合TreeSet来实现,利用TreeSet的构造器或者addAll方法来实现排序,这将在后面的文章中介绍。
这里只给出了LinkedList的排序代码,而对于ArrayList和Vector的排序也是同样的操作,此处不再赘述。